尽管存在此 ImportError,但使用 python 的 sftp 文件传输工作正常。如何消除这个错误?

sftp file transfer using python works fine despite this ImportError. How to remove this error?

我有这个 python 功能可以通过 sftp 上传文件。效果很好。

def sftp_upload(destination, username, password,
                     remote_loc, source_file):
    import pysftp
    with pysftp.Connection(destination, username,
                           password, log="pysftp.log") as sftp:
        sftp.cwd(remote_loc)
        sftp.put(source_file)

    sftp.close()
    return None

代码按预期运行。但是,我总是在结尾 ImportError: sys.meta_path is None, Python is likely shutting down.

收到此错误

如何消除这个错误?我也很疑惑为什么代码会在出错的情况下顺利运行到最后。

在日志文件中,我看到了以下内容;

INF [20220304-18:49:14.727] thr=2   paramiko.transport.sftp: [chan 0] sftp session closed.
DEB [20220304-18:49:14.727] thr=2   paramiko.transport: [chan 0] EOF sent (0)
DEB [20220304-18:49:14.728] thr=1   paramiko.transport: EOF in transport thread

这是堆栈跟踪;

Exception ignored in: <function Connection.__del__ at 0x000001A8B08765E0>
Traceback (most recent call last):
  File "C:\ProgramData\Anaconda3\lib\site-packages\pysftp\__init__.py", line 1013, in __del__
  File "C:\ProgramData\Anaconda3\lib\site-packages\pysftp\__init__.py", line 795, in close
ImportError: sys.meta_path is None, Python is likely shutting down

我正在使用 python v3.9

看起来您的程序在 sftp 对象 garbage-collected 之前结束。 然后,sftp.__del__ 方法在程序的拆卸过程中被调用,这导致了错误。

来自pysftp.py代码:

def __del__(self):
    """Attempt to clean up if not explicitly closed."""
    self.close()

我个人认为应该算是pysftp项目中的一个bug。

我可以想到两个解决方法:

  1. 覆盖 __del__ 方法:

    pysftp.Connection.__del__ = lambda x: None

  2. (不太推荐-效率较低)显式删除sftp对象并触发垃圾回收:

    del sftp; import gc; gc.collect() 就在 with 块之后

注意:import pysftp 在函数之外以某种方式为我解决了这个问题。


这是 pysftp==0.2.9 中的错误。

您可以通过将 close() 覆盖为仅 运行 一次来修复它:

class SFTPConnection(pysftp.Connection):
    def close(self):
        if getattr(self, '_closed', False):
            return
        self._closed = True
        super().close()

用法:

# with pysftp.Connection(destination, username, password=password, log="pysftp.log") as sftp:  # -
with SFTPConnection(destination, username, password=password, log="pysftp.log") as sftp:       # +

参考文献: